package com.py.framework.service.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import com.py.framework.common.Constants;
import com.py.framework.common.UserCacheHelper;
import com.py.framework.common.UserSingleOnline;
import com.py.framework.core.helper.JWTHelper;
import com.py.framework.core.utils.SerializingUtil;
import com.py.framework.entity.AreaEntity;
import com.py.framework.entity.DictDetailEntity;
import com.py.framework.entity.LogEntity;
import com.py.framework.entity.MenuEntity;
import com.py.framework.entity.OfficeEntity;
import com.py.framework.entity.SysMsgEntity;
import com.py.framework.entity.UserEntity;
import com.py.framework.service.AreaService;
import com.py.framework.service.AuthenticationService;
import com.py.framework.service.MenuResourceService;
import com.py.framework.service.OfficeService;
import com.py.framework.service.SysDictService;
import com.py.framework.service.SysLogService;
import com.py.framework.service.SysMsgService;
import com.py.framework.service.UserService;

import io.jsonwebtoken.Claims;

/**
 * 对外接口鉴权数据Service实现
 * 
 * @author Leegern
 * @date 2018年4月26日
 */
@Service
public class AuthenticationServiceImpl implements AuthenticationService {

	@Autowired
	private UserService userService;
	@Autowired
	private OfficeService officeService;
	@Autowired
	private MenuResourceService menuResourceService;
	@Autowired
	private AreaService areaService;
	/** 系统日志Service **/
	@Autowired
	private SysLogService sysLogService;
	@Autowired
	private SysMsgService sysMsgService;
	@Autowired
	private SysDictService sysDictService;

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.py.framework.service.AuthenticationService#getCurrentUser(java.lang.
	 * String)
	 */
	@Override
	public UserEntity getCurrentUserInfo(String jdToken) throws Exception {
		UserEntity userEntity = null;
		long userId = 0L;
		if (StringUtils.isNotBlank(jdToken)) {
			byte[] bts = UserCacheHelper.getUserFromCache(SerializingUtil.serialize(jdToken));
			if (null == bts || bts.length == Constants.NUMBER_ZERO) {
				userId = this.pickUserId(jdToken);
				if (userId > Constants.NUMBER_ZERO) {
					userEntity = userService.findOneUser(userId);
					if (null != userEntity) {
						UserCacheHelper.putUserCache(SerializingUtil.serialize(jdToken),
								SerializingUtil.serialize(userEntity));
					}
				}
			} else {
				userEntity = (UserEntity) SerializingUtil.deserialize(bts);
			}
		}
		return userEntity;
	}

	@Override
	public Integer getAreaIdByDeptId(String id) {
		return officeService.getAreaIdByDeptId(id);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.py.framework.service.AuthenticationService#getCurrentUserOffice(java.
	 * lang.String)
	 */
	@Override
	public OfficeEntity getCurrentUserOffice(String jdToken) throws Exception {
		OfficeEntity officeEntity = null;
		long userId = 0L;
		if (StringUtils.isNotBlank(jdToken)) {
			byte[] bts = UserCacheHelper.getUserOfficeFromCache(SerializingUtil.serialize(jdToken));
			if (null == bts || bts.length == Constants.NUMBER_ZERO) {
				userId = this.pickUserId(jdToken);
				if (userId > Constants.NUMBER_ZERO) {
					officeEntity = officeService.getUserOffice(userId);
					if (null != officeEntity) {
						UserCacheHelper.putUserOfficeCache(SerializingUtil.serialize(jdToken),
								SerializingUtil.serialize(officeEntity));
					}
				}
			} else {
				officeEntity = (OfficeEntity) SerializingUtil.deserialize(bts);
			}
		}
		return officeEntity;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.py.framework.service.AuthenticationService#
	 * getCurrentUserMenuResources(java.lang.String)
	 */
	@SuppressWarnings("unchecked")
	@Override
	public List<MenuEntity> getCurrentUserMenuResources(String jdToken) throws Exception {
		List<MenuEntity> menus = null;
		long userId = 0L;
		if (StringUtils.isNotBlank(jdToken)) {
			UserEntity user = this.getCurrentUserInfo(jdToken);
			// 超级管理员展示所有菜单
			if (null != user && user.getUserType() == 3) {
				menus = menuResourceService.getMenuResourceByMenuType(Constants.NUMBER_ZERO);
			} else {
				byte[] bts = UserCacheHelper.getUserMenuFromCache(SerializingUtil.serialize(jdToken));
				if (null != bts && bts.length > Constants.NUMBER_ZERO) {
					menus = (List<MenuEntity>) SerializingUtil.deserialize(bts);
				} else {
					userId = this.pickUserId(jdToken);
					if (userId > Constants.NUMBER_ZERO) {
						menus = menuResourceService.getUserMenuResources(userId);
						if (!CollectionUtils.isEmpty(menus)) {
							// 缓存用户菜单资源
							UserCacheHelper.putUserMenuCache(SerializingUtil.serialize(jdToken),
									SerializingUtil.serialize(menus));
							// 缓存用户资源数据
							UserCacheHelper.putUserResourcesCache(SerializingUtil.serialize(jdToken),
									SerializingUtil.serialize(this.populateResources(menus)));
						}
					}
				}
			}
		}
		return menus;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.py.framework.service.AuthenticationService#getCurrentUserOffices(java
	 * .lang.String)
	 */
	@Override
	public List<OfficeEntity> getCurrentUserOffices(String jdToken) throws Exception {
		List<OfficeEntity> result = new ArrayList<>();
		long officeId = 0;
		if (StringUtils.isNotBlank(jdToken)) {
			OfficeEntity office = this.getCurrentUserOffice(jdToken);
			if (null != office && (officeId = office.getId()) > Constants.NUMBER_ZERO) {
				List<OfficeEntity> datas = officeService.getOfficesByParentId(String.valueOf(officeId));
				result.add(office);
				result.addAll(datas);
			}
		}
		return result;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.py.framework.service.AuthenticationService#getCurrentUserAreas(java.
	 * lang.String)
	 */
	@Override
	public List<AreaEntity> getCurrentUserAreas(String jdToken) throws Exception {
		List<AreaEntity> result = new ArrayList<>();
		if (StringUtils.isNotBlank(jdToken)) {
			OfficeEntity office = this.getCurrentUserOffice(jdToken);
			if (null != office && office.getAreaId() > Constants.NUMBER_ZERO) {
				List<AreaEntity> areas = this.getAllAreasById(office.getAreaId());
				if (!CollectionUtils.isEmpty(areas)) {
					result.addAll(areas);
				}
			}
		}
		return result;
	}

	/*
	 * * (non-Javadoc)
	 * 
	 * @see
	 * com.py.framework.service.AuthenticationService#hasValidResource(java.lang
	 * .String, java.lang.String)
	 */
	@SuppressWarnings("unchecked")
	@Override
	public boolean hasValidResource(String jdToken, String resource) throws Exception {
		boolean result = false;
		Map<String, String> resources = null;
		byte[] bts = UserCacheHelper.getUserResourcesFromCache(SerializingUtil.serialize(jdToken));
		if (null != bts && bts.length > 0) {
			resources = (Map<String, String>) SerializingUtil.deserialize(bts);
			if (!CollectionUtils.isEmpty(resources) && resources.containsKey(resource)) {
				result = true;
			}
		} else {
			long userId = this.pickUserId(jdToken);
			if (userId > Constants.NUMBER_ZERO) {
				List<MenuEntity> menus = menuResourceService.getUserMenuResources(userId);
				if (!CollectionUtils.isEmpty(menus)) {
					// 缓存用户菜单资源
					UserCacheHelper.putUserMenuCache(SerializingUtil.serialize(jdToken),
							SerializingUtil.serialize(menus));
					resources = this.populateResources(menus);
					if (!CollectionUtils.isEmpty(resources)) {
						result = resources.containsKey(resource);
						// 缓存用户资源数据
						UserCacheHelper.putUserResourcesCache(SerializingUtil.serialize(jdToken),
								SerializingUtil.serialize(resources));
					}
				}
			}
		}
		return result;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.py.framework.service.AuthenticationService#getAllAreasById(long)
	 */
	@Override
	public List<AreaEntity> getAllAreasById(long areaId) {
		if (areaId > Constants.NUMBER_ZERO) {
			return areaService.getAreasByParentId(String.valueOf(areaId));
		} else {
			return areaService.getAllAreas();
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.py.framework.service.AuthenticationService#getRootArea()
	 */
	@Override
	public AreaEntity getRootArea() {
		AreaEntity area = null;
		List<AreaEntity> rootAreas = areaService.getRootArea();
		if (!CollectionUtils.isEmpty(rootAreas)) {
			area = rootAreas.get(0);
		}
		return area;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.py.framework.service.AuthenticationService#getSecondAreas()
	 */
	@Override
	public List<AreaEntity> getSecondAreas() {
		AreaEntity area = this.getRootArea();
		if (null != area && area.getId() > Constants.NUMBER_ZERO) {
			return areaService.getSecondAreas(area.getId());
		}
		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.py.framework.service.AuthenticationService#getAreasByparentId(long)
	 */
	@Override
	public List<AreaEntity> getAreasByParentId(long parentId) {
		if (parentId > Constants.NUMBER_ZERO) {
			return areaService.getAreasByPid(parentId);
		}
		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.py.framework.service.AuthenticationService#getAreasByIds()
	 */
	@Override
	public List<AreaEntity> getAreasByIds(List<Long> ids) {
		return areaService.getAreasByIds(ids);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.py.framework.service.AuthenticationService#getUsersByIds(java.util.
	 * List)
	 */
	@Override
	public List<UserEntity> getUsersByIds(List<Long> ids) {
		if (!CollectionUtils.isEmpty(ids)) {
			return userService.getUsersByIds(ids);
		}
		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.py.framework.service.AuthenticationService#getSubUsersById(long)
	 */
	@Override
	public List<UserEntity> getSubUsersById(long userId) {
		if (userId > Constants.NUMBER_ZERO) {
			return userService.getSubUsersById(userId);
		}
		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.py.framework.service.AuthenticationService#getRootOffices()
	 */
	@Override
	public List<OfficeEntity> getRootOffices() {
		return officeService.getRootOffices();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.py.framework.service.AuthenticationService#getOfficeById(long)
	 */
	@Override
	public OfficeEntity getOfficeById(long officeId) {
		if (officeId > Constants.NUMBER_ZERO) {
			return officeService.findOneOffice(officeId);
		}
		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.py.framework.service.AuthenticationService#getOfficesByAreaId(long)
	 */
	@Override
	public List<OfficeEntity> getOfficesByAreaId(long areaId) {
		if (areaId > Constants.NUMBER_ZERO) {
			return officeService.getOfficesByAreaId(areaId);
		}
		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.py.framework.service.AuthenticationService#getAllOffices()
	 */
	@Override
	public List<OfficeEntity> getAllOffices() {
		return officeService.getAllOffices();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.py.framework.service.AuthenticationService#putUserSessionData(java.
	 * lang.String, com.py.framework.entity.UserEntity)
	 */
	@Override
	public void putUserSessionData(String jdToken, UserEntity user) {
		// 缓存用户信息
		UserCacheHelper.putUserCache(SerializingUtil.serialize(jdToken), SerializingUtil.serialize(user));
		// 缓存用户部门
		OfficeEntity office = officeService.getUserOffice(user.getId());
		if (null != office) {
			UserCacheHelper.putUserOfficeCache(SerializingUtil.serialize(jdToken), SerializingUtil.serialize(office));
		}
		// 将用户添加到在线列表
		UserSingleOnline.putInCache(user.getUsername(), jdToken);
		// 缓存用户菜单资源
		List<MenuEntity> menus = menuResourceService.getUserMenuResources(user.getId());
		if (!CollectionUtils.isEmpty(menus)) {
			// 缓存用户菜单资源
			UserCacheHelper.putUserMenuCache(SerializingUtil.serialize(jdToken), SerializingUtil.serialize(menus));
			// 缓存用户资源数据
			UserCacheHelper.putUserResourcesCache(SerializingUtil.serialize(jdToken),
					SerializingUtil.serialize(this.populateResources(menus)));
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.py.framework.service.AuthenticationService#clearUserSessionData(java.
	 * lang.String)
	 */
	@Override
	public void clearUserSessionData(String jdToken) {
		if (StringUtils.isNotBlank(jdToken)) {
			// 清空用户信息
			UserCacheHelper.clearUserCache(SerializingUtil.serialize(jdToken));
			// 清除在线用户令牌
			UserSingleOnline.clearUserTokens(Arrays.asList(jdToken));
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.py.framework.service.AuthenticationService#sendLogToQueue(com.py.
	 * framework.entity.LogEntity)
	 */
	@Override
	public void sendLogToQueue(LogEntity entity) {
		sysLogService.sendToQueue(entity);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.py.framework.service.AuthenticationService#sendSysMsg(java.lang.
	 * String, com.py.framework.entity.SysMsgEntity)
	 */
	@Override
	public int sendSysMsg(String jdToken, List<SysMsgEntity> entities) throws Exception {
		if (!CollectionUtils.isEmpty(entities)) {
			long userId = 0L;
			if (StringUtils.isNotBlank(jdToken)) {
				userId = this.pickUserId(jdToken);
			}
			for (SysMsgEntity entity : entities) {
				entity.setSendId(userId);
				sysMsgService.addMsgInfo(entity);
			}
			return entities.size();
		}
		return 0;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.py.framework.service.AuthenticationService#getDictDetails(java.lang.
	 * String)
	 */
	@Override
	public List<DictDetailEntity> getDictDetails(String dictKey) {
		if (StringUtils.isNotBlank(dictKey)) {
			return sysDictService.getDictDetails(dictKey, StringUtils.EMPTY);
		}
		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.py.framework.service.AuthenticationService#getDictDetail(java.lang.
	 * String,java.lang.String)
	 */
	@Override
	public DictDetailEntity getDictDetail(String dictKey, String dtlKey) {
		if (StringUtils.isNotBlank(dictKey) && StringUtils.isNotBlank(dtlKey)) {
			List<DictDetailEntity> datas = sysDictService.getDictDetails(dictKey, dtlKey);
			if (!CollectionUtils.isEmpty(datas)) {
				return datas.get(Constants.NUMBER_ZERO);
			}
		}
		return null;
	}

	@Override
	public List<UserEntity> getAllDeptAdmin(List<Long> deptIds) {
		return userService.getAllDeptAdmin(deptIds);
	}

	@Override
	public List<Long> getDeptManager(List<Long> deptIds) {
		return userService.getDeptManager(deptIds);
	}

	/**
	 * 解密用户Id
	 * 
	 * @param jdToken
	 *            令牌
	 * @return
	 * @throws Exception
	 */
	private long pickUserId(String jdToken) throws Exception {
		Claims claims = JWTHelper.parseJWT(jdToken);
		long userId = 0L;
		if (null != claims && StringUtils.isNotBlank(claims.getSubject())) {
			userId = Long.parseLong(claims.getId());
		}
		return userId;
	}

	/**
	 * 组装资源
	 * 
	 * @param menus
	 *            菜单集合
	 * @return
	 */
	private Map<String, String> populateResources(List<MenuEntity> menus) {
		Map<String, String> result = new HashMap<>();
		if (!CollectionUtils.isEmpty(menus)) {
			for (MenuEntity menuEntity : menus) {
				if (StringUtils.isNotBlank(menuEntity.getLinkUrl())) {
					result.put(menuEntity.getLinkUrl(), menuEntity.getLinkUrl());
				}
			}
		}
		return result;
	}

	@Override
	public List<Map> getLoginTimesByDept() {
		// TODO Auto-generated method stub
		return sysLogService.getLoginTimesByDept();
	}

	@Override
	public List<UserEntity> getDeptAllUsers(String deptId) {
		return userService.getDeptAllUsers(deptId);
	}

	@Override
	public List<LinkedHashMap> seletctDictInfo() {
		
		return sysDictService.seletctDictInfo();
	}

	@Override
	public List<UserEntity> getUsers() {
		return userService.getAllUsers();
	}

}